#include "Rodeur.h"

#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost::assign;

const unsigned int Rodeur::nbr_comp = 16;

const unsigned int Rodeur::nbr_restric = 5;

const vector<ListComp> Rodeur::Comp = list_of
  (ListComp("Combat ambidextre"               ,  5))
  (ListComp("Déplacement silencieux"          ,  5))
  (ListComp("Détecter les bruits"             , 10))
  (ListComp("Empathie animale"                , 10))
  (ListComp("Ennemi juré"                     , 10))
  (ListComp("Grimper"                         , 10))
  (ListComp("Langage des animaux"             ,  5))
  (ListComp("Neutralisation"                  , 10))
  (ListComp("Passage sans trace"              , 10))
  (ListComp("Pistage"                         ,  5))
  (ListComp("Se cacher dans l'ombre"          ,  5))
  (ListComp("Sorts cléricaux"                 , 10))
  (ListComp("Spécialisation"                  , 10))
  (ListComp("Suivants"                        , 10))
  (ListComp("Talent pour les arcs"            ,  5))
  (ListComp("Trouver et désamorcer les pièges", 10));

const vector<ListComp> Rodeur::Restric = list_of
  (ListComp("Limitation d'armes"                         ,  5))
  (ListComp("Limitation à la maille"                     ,  5))
  (ListComp("Limitation au cuir clouté"                  , 10))
  (ListComp("Sans armure"                                , 15))
  (ListComp("Restriction d'utilisation d'objets magiques",  0));

/** Constructeur usuel.
 * Permet la construction d'un paladin de A à Z, càd on détermine ici
 * les restrictions, puis les compétences.
 * @param xp le nombre de pts d'expérience du Rôdeur.
 * @param trait les traits du Rôdeur, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 * @param PP nombre de points de personnage (PP) à disposition pour la
 * céation du Rôdeur.
 */
Rodeur::Rodeur(unsigned int xp, unsigned int trait[7], unsigned int& PP)
  : Classe(xp, trait, Combattants)
{
  Type_classe = "Rôdeur";
  PP += 60;
  ptrComp = &Comp;
  ptrRes  = &Restric;
  ptrNbrComp = &nbr_comp;
  ptrNbrRes  = &nbr_restric;
  blank() << setfill('*') << setw(56) << '*' << endreq;
  blank() << "Création d'un rôdeur" << endl << endreq;
  unsigned int nbr(0);
 
  for (unsigned int i(0); i<nbr_restric; i++)
    {
      if (Restric[i].Cout != 0)
	blank() << i+1 << ' ' << Restric[i].Comp << " ("
		    << Restric[i].Cout << " pp)" << endreq;
      else
	blank() << i+1 << ' ' << Restric[i].Comp << " (cout variable)"
		    << endreq;	
    }
  blank() << nbr_restric+1 << " Aucune" << endreq;
  blank() << "Choisir les restrictions" << endreq;
  
  bool test(true), deja_pris, encore(false);
  unsigned int save_PP(PP);

  do
    {
      do
	{
	  nbr = demander_unsigned_borne("Choisir les restrictions ", 1,
					nbr_restric + 1);
	  if (nbr!=nbr_restric+1)
	    {
	      if (Restric[nbr-1].Cout == 0)
		{
		  deja_pris = safe_push_back(&Comp_classe, 15+nbr);
		  if (deja_pris)
		    warning() << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(15+nbr);
		      unsigned int pps;
		      pps =  demander_unsigned("Entrez les PP obtenus : ");
		      PP += pps;
		      blank() << "Restriction choisie : "
				  << Restric[nbr-1].Comp << endreq;
		    }
		}
	      else
		{
		  deja_pris = safe_push_back(&Comp_classe, 15+nbr);
		  if (deja_pris)
		    warning() << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(15+nbr);
		      PP += Restric[nbr-1].Cout;
		      blank() << "Restriction choisie : "
				  << Restric[nbr-1].Comp << endreq;
		    }
		}
	    }
	  else
	    test = false;
	}
      while(test);

      affiche_competences();
      blank() << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
      nbr = demander_unsigned_borne("Choix ", 1, 2);
      if (nbr == 2)
	{
	  PP = save_PP;
	  Comp_classe.clear();
	  test = true;
	  encore = true;
	  blank() << endreq;
	}
      else
	encore = false;
    }
  while(encore);

  test = true;

  blank() << "Tu as " << PP << " pp à dépenser" << endreq;
  save_PP = PP;

  for (unsigned int i(0); i<nbr_comp; i++)
    {
      if (Comp[i].Cout != 0)
	blank() << i+1 << ' ' << Comp[i].Comp << " (" << Comp[i].Cout
		    << " pp)" << endreq;
      else
	blank() << i+1 << ' ' << Comp[i].Comp << " (cout variable)"
		    << endreq;	
    }
  blank() << nbr_comp+1 << " Aucune" << endreq;
  blank() << "Choisir les compétences de classe" << endreq;

  do
    {
      do
	{
	  nbr = demander_unsigned_borne("("+write_int(PP)+" restants) ", 1,
					nbr_comp + 1);
	  if (nbr!=nbr_comp+1)
	    {
	      if (PP >= Comp[nbr-1].Cout)
		{
		  deja_pris = safe_push_back(&Comp_classe, nbr - 1);
		  if (deja_pris)
		    warning() << "Déjà sélectionné" << endreq;
		  else
		    {
		      Comp_classe.push_back(nbr-1);
		      PP -= Comp[nbr-1].Cout;
		      blank() << "Compétence choisie : " << Comp[nbr-1].Comp
				  << endreq;
		    }
		}
	      else
		blank() << "Pas assez de pp" << endreq;
	    }
	  else
	    test = false;
	}
      while(test);

      affiche_competences();
      blank() << endl <<  "1 pour continuer, 2 pour recommencer" << endreq;
      nbr = demander_unsigned_borne("Choix ", 1, 2);
      if (nbr == 2)
	{
	  PP = save_PP;
	  while(Comp_classe.back() < nbr_comp)
	    Comp_classe.pop_back();
	  test = true;
	  encore = true;
	  blank() << endreq;
	}
      else
	encore = false;
    }
  while(encore);

  blank() << endl << setfill('*') << setw(56) << '*' << endreq;
  calcul_niveau();
  calcul_niv_mag();
}

/** Constructeur simplifié.
 * Permet de construire un Rôdeur lors de la lecture d'un ficier xml.
 * @param xp le nombre de pts d'expérience du Rôdeur.
 * @param trait les traits du Rôdeur, le 7ème contient le score de
 * force exceptionnel, fixé à 0 si non applicable.
 */
Rodeur::Rodeur(unsigned int xp, unsigned int trait[7])
  : Classe(xp, trait, Combattants)
{
  Type_classe = "Rôdeur";
  ptrComp = &Comp;
  ptrRes  = &Restric;
  ptrNbrComp = &nbr_comp;
  ptrNbrRes  = &nbr_restric;
  calcul_niveau();
  calcul_niv_mag();
}

Rodeur::Rodeur(unsigned int xp, unsigned int trait[7], const bool& UI)
  : Classe(xp, trait, Combattants)
{
  if (!UI)
    {
      error() << "Création du personnage impossible" << endreq;
      exit(1);
    }

  Type_classe = "Rôdeur";
  ptrComp = &Comp;
  ptrRes  = &Restric;
  ptrNbrComp = &nbr_comp;
  ptrNbrRes  = &nbr_restric;
  calcul_niveau();
  calcul_niv_mag();
}

/** 
 * Destructeur, ne fait rien.
 */
Rodeur::~Rodeur()
{}

void Rodeur::calcul_niveau()
{
  if (XP < 75000)
    {
      unsigned int i;
      for (i = 0; i < 5; i++)
	{
	  if (XP < (unsigned int) 2250 * puissance(2, i))
	    break;
	}
      Niveau = i + 1;
    }
  else if (XP < 150000)
    Niveau = 7;
  else if (XP < 300000)
    Niveau = 8;
  else
      Niveau = (XP - 300000) / 300000 + 9;
}

// void Rodeur::afficher_stats(ostream& os)
// {
//   os << "Rôdeur" << endreq;
//   os << "Niveau " << Niveau << ", niveau de magie " << Niveau_mag << endreq;
//   for (unsigned int i(0); i < 6; i++)
//     os << Caracteristiques[i] << ' ' <<Traits[i] << endreq;
//   for (unsigned int i(0); i < Comp_classe.size(); i++)
//     {
//       if(Comp_classe[i] >= nbr_comp)
// 	os << Restric[Comp_classe[i] - nbr_comp].Comp << endreq;
//       else
// 	os << Comp[Comp_classe[i]].Comp << endreq;
//     }
// }

void Rodeur::appliquer_modif(const string& type)
{}

void Rodeur::augmenter_talents(const unsigned int& bonus, const bool& lvl_up)
{}

void Rodeur::get_JS(unsigned int *tab) const
{
  *(tab + 0) = 14; // Paralysie, Poison ou Mort magique
  *(tab + 1) = 16; // Bâton, batonnet baguette
  *(tab + 2) = 15; // Pétrification ou Métamorphose
  *(tab + 3) = 17; // Souffles
  *(tab + 4) = 17; // Sorts
  
  unsigned int cat;
  if (Niveau <= 2)
    cat = 0;
  else  if (Niveau <= 4)
    cat = 1;
  else  if (Niveau <= 6)
    cat = 3;
  else  if (Niveau <= 8)
    cat = 4;
  else  if (Niveau <= 10)
    cat = 6;
  else  if (Niveau <= 12)
    cat = 7;
  else  if (Niveau <= 14)
    cat = 9;
  else  if (Niveau <= 16)
    cat = 10;
  else
    cat = 11;

  *(tab + 0) -= cat;
  *(tab + 1) -= cat;
  *(tab + 2) -= cat;
  *(tab + 3) -= cat;
  *(tab + 4) -= cat;

  if (cat == 3)
    *(tab + 3) = 13;
  else if (cat == 4)
    *(tab + 3) = 12;
  else if (cat == 4)
    *(tab + 3) = 9;
  else if (cat == 6)
    *(tab + 3) = 8;
  else if (cat == 7)
    *(tab + 3) = 5;
  else if (cat >= 10)
    *(tab + 3) = 4;
}

string Rodeur::get_competence(const unsigned int& i) const
{
  if (get_comp(i) < nbr_comp)
    return Comp[get_comp(i)].Comp;
  else
    return Restric[get_comp(i)-nbr_comp].Comp;
}

unsigned int Rodeur::calcule_TAc0() const
{
  return 21 - Niveau;
}

/**
 * Le Rôdeur aquiert des sorts de prêtre au niveau 9, s'il possède la
 * compétence.
 */
void Rodeur::calcul_niv_mag()
{
  if (Niveau < 8)
    Niveau_mag = 0;
  else if (Niveau < 14)
    Niveau_mag = (Niveau - 7) / 2;
  else
    Niveau_mag = 3;
}

/**
 * Le Rôdeur peut prende la compétence "Sorts cléricaux", qui lui donne
 * accès dès le niveau 9 aux sphères Animale et Végétale.
 */
void Rodeur::ecrire_sorts(const string& nom_fichier, const bool& ecrase) const
{
  bool a_des_sort(false);
  for (unsigned int i(0); i < get_combien(); i++)
    {
      if (get_comp(i) == 9)
	{
	  a_des_sort = true;
	  break;
	}
    }
  ofstream sortie;
  if (ecrase)
    sortie.open(nom_fichier.c_str());
  else
    sortie.open(nom_fichier.c_str(), ios::app);
  if (a_des_sort)
    {
      for (unsigned int i(1); i <= Niveau_mag; i++)
	  sortie << "\\input{Sorts_clerc/Animale_" + write_int(i) + ".inc.tex}" << endreq;
      for (unsigned int i(1); i <= Niveau_mag; i++)
	  sortie << "\\input{Sorts_clerc/Végétale_" + write_int(i) + ".inc.tex}" << endreq;
    }
  else
    sortie << "% Rodeur sans sorts" << endreq;
  sortie.close();
}

void Rodeur::nbr_sort(unsigned int sorts[], const unsigned int& taille) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  debug() << "Fait rien pour le moment" << endreq;
  dout.setLevel(etat_precedent);
}

/**
 * Permet de gérer les compétences martiales, càd lesquelles sont accessibles
 * à quel coût.
 *
 * Pour un Rôdeur, comme pour tous les combattants, le coût est de 3 pour
 * n'importe quelle arme. De plus, il peut acquérir un groupe restreint pour
 * 4 pp et un groupe large pour 5 pp.
*/
void Rodeur::get_prix_acces(map<string, unsigned int>* Map) const
{
  DebugLevelType etat_precedent(dout.getLevel());
  dout.setLevel(fonction);
  func() << "Rodeur::get_prix_acces -> début" << endreq;

  map<string, unsigned int>::const_iterator mapIt, mapBegin(Map -> begin()),
    mapEnd(Map -> end());

  for (mapIt = mapBegin; mapIt != mapEnd; mapIt++)
    {
      lfunc() << mapIt -> first << endreq;
    }
  Map -> operator[]("Rôdeur") = 2;
  
  func() << "Rodeur::ajout_sorts -> fin" << endreq;
  dout.setLevel(etat_precedent);
}
